﻿#include <QCoreApplication>
#include <QFile>
#include <QMap>
#include <QDebug>
#include <QVector>
#include <random>
#include "cu/worker.h"
#include "D:/work/qt/mySnarkVM/rustapi.h"
#include "cu/BigInt.h"

#include <boost/multiprecision/cpp_int.hpp>
typedef boost::multiprecision::uint256_t b_uint256_t;

uint8_t epoch_hash_bytes[] = { 0x09, 0x91, 0xa7, 0xa4, 0x4d, 0xee, 0xbb, 0xe7, 0x5a, 0x64, 0xc4, 0xe1, 0x85, 0x3a, 0x1e, 0xad, 0x48, 0xd8, 0xa9, 0x98, 0x3c, 0x97, 0xe5, 0xf2, 0x39, 0xf3, 0x7a, 0xc1, 0x3d, 0xbf, 0x8f, 0x12 };
uint8_t address_bytes[] = { 0x26, 0xab, 0x19, 0x72, 0x41, 0xa7, 0x46, 0x4b, 0xea, 0x5b, 0x9e, 0x40, 0x9b, 0x2a, 0x60, 0xb8, 0x0a, 0x9e, 0x9a, 0xf8, 0x57, 0x3f, 0x43, 0x3f, 0x6f, 0xc3, 0xeb, 0x55, 0xde, 0x4a, 0x92, 0x0c };
QString g_inst;
bool g_checkInst = false;

QString readFile(QString filename)
{
    QFile file(filename);
    if (!file.open(QFile::ReadOnly | QFile::Text))
    {
        qDebug() << "open file failed";
        return QString();
    }

    return QString::fromUtf8(file.readAll());
}

class Compiler
{
public:
    Compiler()
    {
        m_constRegIndex = 0;

        doubleOp = QStringList{ "add" , "add.w" , "div", "div.w", "mul", "mul.w" , "sub" , "sub.w" , "lt" , "lte" ,
                         "gt" , "gte" , "and", "nor" , "is.eq" , "is.neq" , "mod"  , "pow" , "pow.w",
                         "shl" , "shl.w" , "shr" , "shr.w", "xor", "or", "and", "nand","rem", "rem.w" };
        singleOp = QStringList{ "abs" , "abs.w" , "inv" , "neg" , "square" , "double", "cast.lossy","not" };
        thridOp = QStringList{ "ternary" };
        hashOp = QStringList{ "hash.bhp256" , "hash.bhp512" , "hash.bhp768" , "hash.bhp1024", "hash.keccak256",
                            "hash.keccak384" , "hash.keccak512" , "hash.ped64" , "hash.ped128",
                            "hash.psd2" , "hash.psd4" , "hash.psd8" , "hash.sha3_256" , "hash.sha3_384" , "hash.sha3_512" };

        QStringList op_list;
        op_list.append(singleOp);
        op_list.append(doubleOp);
        op_list.append(thridOp);
        op_list.append(hashOp);

        immType["boolean"] = boolean;
        immType["i8"] = i8;
        immType["i16"] = i16;
        immType["i32"] = i32;
        immType["i64"] = i64;
        immType["i128"] = i128;
        immType["u8"] = u8;
        immType["u16"] = u16;
        immType["u32"] = u32;
        immType["u64"] = u64;
        immType["u128"] = u128;
        immType["field"] = field;

        instType["add"] = Inst_add;
        instType["add.w"] = Inst_addW;
        instType["div"] = Inst_div;
        instType["div.w"] = Inst_divW;
        instType["mul"] = Inst_mul;
        instType["mul.w"] = Inst_mulW;
        instType["sub"] = Inst_sub;
        instType["sub.w"] = Inst_subW;
        instType["lt"] = Inst_lt;
        instType["lte"] = Inst_lte;
        instType["gt"] = Inst_gt;
        instType["gte"] = Inst_gte;
        instType["nor"] = Inst_nor;
        instType["is.eq"] = Inst_isEq;
        instType["is.neq"] = Inst_isNeq;
        instType["mod"] = Inst_mod;
        instType["pow"] = Inst_pow;
        instType["pow.w"] = Inst_powW;
        instType["shl"] = Inst_shl;
        instType["shl.w"] = Inst_shlW;
        instType["shr"] = Inst_shr;
        instType["shr.w"] = Inst_shrW;
        instType["xor"] = Inst_xor;
        instType["or"] = Inst_or;
        instType["and"] = Inst_and;
        instType["nand"] = Inst_nand;
        instType["rem"] = Inst_rem;
        instType["rem.w"] = Inst_remW;
        instType["abs"] = Inst_abs;
        instType["abs.w"] = Inst_absW;
        instType["inv"] = Inst_inv;
        instType["neg"] = Inst_neg;
        instType["square"] = Inst_square;
        instType["double"] = Inst_double;
        instType["cast.lossy"] = Inst_castLossy;
        instType["not"] = Inst_not;
        instType["ternary"] = Inst_ternary;
        instType["hash.bhp256"] = Inst_hashBhp256;
        instType["hash.bhp512"] = Inst_hashBhp512;
        instType["hash.bhp765"] = Inst_hashBhp768;
        instType["hash.bhp1024"] = Inst_hashBhp1024;
        instType["hash.keccak256"] = Inst_hashKeccak256;
        instType["hash.keccak384"] = Inst_hashKeccak384;
        instType["hash.keccak512"] = Inst_hashKeccak512;
        instType["hash.ped64"] = Inst_hashPed64;
        instType["hash.ped128"] = Inst_hashPed128;
        instType["hash.psd2"] = Inst_hashPsd2;
        instType["hash.psd4"] = Inst_hashPsd4;
        instType["hash.psd8"] = Inst_hashPsd8;
        instType["hash.sha3_256"] = Inst_hashSha3_256;
        instType["hash.sha3_384"] = Inst_hashSha3_384;
        instType["hash.sha3_512"] = Inst_hashSha3_512;
    }

    QString error()
    {
        return m_error;
    }

    bool parseInst(QString input, Instruction& inst)
    {
        input = input.toLower().simplified();
        if (input.endsWith(";"))
            input.chop(1);

        QStringList strs = input.split(" ");
        QString type = strs[0];

        inst.type = instType[type];
        if (doubleOp.contains(type))
        {
            inst.inOp[0] = toReg(strs[1]);
            inst.inOp[1] = toReg(strs[2]);
            inst.inOpSize = 2;
            inst.outOp = toReg(strs[4]);
        }
        else if (singleOp.contains(type))
        {
            inst.inOp[0] = toReg(strs[1]);
            inst.inOpSize = 1;
            inst.outOp = toReg(strs[3]);
        }
        else if (hashOp.contains(type))
        {
            inst.inOp[0] = toReg(strs[1]);
            inst.inOpSize = 1;
            inst.outOp = toReg(strs[3]);
        }
        else if (thridOp.contains(type))
        {
            inst.inOp[0] = toReg(strs[1]);
            inst.inOp[1] = toReg(strs[2]);
            inst.inOp[2] = toReg(strs[3]);
            inst.inOpSize = 3;
            inst.outOp = toReg(strs[5]);
        }
        else
        {
            m_error = "unkonw op " + type;
            return false;
        }

        //eval
        for (int i = 0; i < inst.inOpSize; i++)
        {
            if (!m_regTypes.contains(inst.inOp[i]))
            {
                m_error = "no reg r" + QString::number(inst.inOp[i]);
                return false;
            }
        }

        QVector<int> inst_hashOp = { Inst_hashPsd2,Inst_hashBhp256,Inst_hashPed64 };
        QVector<int> cmpOp = { Inst_lt, Inst_lte, Inst_gt, Inst_gte, Inst_isEq, Inst_isNeq };

        int out_type = -1;
        if (cmpOp.contains(inst.type))
        {
            out_type = boolean;
        }
        else if (inst_hashOp.contains(inst.type)
            || inst.type == Inst_castLossy)
        {
            QStringList strs = input.split(" ");
            out_type = toType(strs[5]);
        }
        else
        {
            int op;
            if (inst.type == Inst_ternary)
                op = inst.inOp[1];
            else
                op = inst.inOp[0];

            out_type = m_regTypes[op];
        }

        if (out_type == -1)
        {
            m_error = "can't calc out type";
            return false;
        }

        m_regTypes[inst.outOp] = out_type;
        return true;
    }

    bool compiler(QString code, Program* program)
    {
        m_program = program;
        memset(program, 0, sizeof(Program));

        m_constRegIndex = CONST_REG_START;
        m_constRegOffset = 0;
        m_constReg.clear();

        auto lines = code.split("\n");
        int inst_count = 0;
        for (int i = 0; i < lines.size(); i++)
        {
            auto line = lines[i].simplified();
            if (line.isEmpty())
                continue;

            if (line.startsWith("input"))
            {
                if (line.endsWith(";"))
                    line.chop(1);

                QStringList strs = line.split(" ");
                if (strs.size() != 4)
                {
                    m_error = line + " format error";
                    return false;
                }

                //strs[0]
                QString reg = strs[1];
                QString type = strs[3];
                if (type.endsWith(".public"))
                    type.chop(7);

                program->inputRegSize++;
                m_regTypes[toReg(reg)] = toType(type);
            }
            else
            {
                Instruction inst;
                memset(&inst, 0, sizeof(inst));
                if (!parseInst(line, inst))
                    return false;

                program->inst[inst_count++] = inst;
            }
        }

        auto it = m_regTypes.begin();
        while (it != m_regTypes.end())
        {
            program->regType[it.key()] = it.value();
            it++;
        }

        program->instSize = inst_count;
        m_program->constRegSize = m_constRegIndex - CONST_REG_START;
        return true;
    }

    int toType(QString str)
    {
        if (str == "false" || str == "true")
            return boolean;

        auto it = immType.begin();
        while (it != immType.end())
        {
            if (str.endsWith(it.key()))
                return it.value();

            it++;
        }

        Q_ASSERT(0);
        return -1;
    }

    int toReg(QString str)
    {
        if (str.startsWith('r'))
            return str.mid(1).toInt();
        else
        {
            if (!m_constReg.contains(str))
            {
                int const_type = toType(str);
                m_program->regType[m_constRegIndex] = const_type;
                m_constReg[str] = m_constRegIndex;
                m_regTypes[m_constRegIndex] = const_type;

                QByteArray buffer = toBitsLe(str);

                int byte_size = (typeBitSize(const_type) + 7)/8;
                memcpy(m_program->constValue + m_constRegOffset, buffer.data(), byte_size);
                m_constRegOffset += byte_size;

                m_constRegIndex++;
            }

            return m_constReg[str];
        }
    }

    QByteArray toBitsLe(QString str)
    {
        int const_type = toType(str);
        int byte_size = (typeBitSize(const_type) + 7) / 8;

        if (str == "false" || str == "true")
        {
        }
        else
        {
            auto it = immType.begin();
            while (it != immType.end())
            {
                if (str.endsWith(it.key()))
                {
                    str = str.left(str.size() - it.key().size());
                    break;
                }

                it++;
            }
        }

        b_uint256_t data(qPrintable(str));
        QByteArray buffer(32, 0);
        boost::multiprecision::export_bits(data, buffer.data(), 8, false);

        return buffer.mid(0, byte_size);
    }

    int typeBitSize(int v_type)
    {
        if (v_type == Type::boolean)
        {
            return 1;
        }
        if (v_type == Type::i8)
        {
            return 8;
        }
        else if (v_type == Type::i16)
        {
            return 16;
        }
        else if (v_type == Type::i32)
        {
            return 32;
        }
        else if (v_type == Type::i64)
        {
            return 64;
        }
        else if (v_type == Type::i128)
        {
            return 128;
        }
        else if (v_type == Type::u8)
        {
            return 8;
        }
        else if (v_type == Type::u16)
        {
            return 16;
        }
        else if (v_type == Type::u32)
        {
            return 32;
        }
        else if (v_type == Type::u64)
        {
            return 64;
        }
        else if (v_type == Type::u128)
        {
            return 128;
        }
        else if (v_type == Type::field)
        {
            return 253;
        }

        return 0;
    }

    QString m_error;
    QMap<int, int> m_regTypes;
    QMap<QString, QStringList> opTypeMap;
    QStringList singleOp;
    QStringList doubleOp;
    QStringList thridOp;
    QStringList hashOp;
    QMap<QString, int> immType;
    QMap<QString, int> instType;

    Program* m_program;
    QMap<QString, int> m_constReg;
    int m_constRegIndex;
    int m_constRegOffset;
};

void init_device_constant()
{
    QString p_str = R"(8444461749428370424248824938781546531375899335154063827935233455917409239041,8444461749428370424248824938781546531375899335154063827935233455917409239040,3021)";

    QString ark_str = R"([[1370773116404421539888881648821194629032979299946048429076387284005101684675field.constant, 467303563782581760903851473353955518531379166602363396166335208066583
0654830field.constant, 3476986714632640194314485873881082667866912997891863048915892042674874286264field.constant], [108249527826648275483356262175830863258136636510871
8780801560341752506567697field.constant, 4949432510532674124503328437030614426007112126335799011165573383397503068558field.constant, 13307312684212568362507051365674423
17504087954921291231955447229193812596308field.constant], [2649505161225663922316999879032136225486779063673300240621719420078616600331field.constant, 49694205877036796
12645522006695883166296724515300508402438681500077273342102field.constant, 205635712587803026777585519450868615715404988831679984758308345484658244699field.constant], [
6145772648854219628629735661952781083869402744236565775495743574991105198727field.constant, 5694971131555029816374722311330556638260056256238039903705739439184187043937
field.constant, 5741725876337992913741719090196370235271299497940404104226910654118627348231field.constant], [6469638413629030129780219709477213488269112947492045389237
429028620220258446field.constant, 3701595212702118832843766258638566924918883592466668319824165091176624488470field.constant, 378826417211332007192937550565441062167288
0197708720070568683533593741188367field.constant], [7440115096888436553805393179190448787187286166192882400220572931865568317182field.constant, 792346028642694686435936
057983036575794551345818605100013220351237266490211field.constant, 3512073197867644095949820682768614757198377867832806840119595329029395413419field.constant], [3327088
580126882425803902509250293076948968718390152099056814690231480975540field.constant, 7158369207426751973498757672315193862013926247640641608613447343948389969907field.c
onstant, 6576114422707630183258306285876174832535448513519868242206479550748199028650field.constant], [17504413292168042851315738384079889745370001089199141172513832153
90240334007field.constant, 6643642586767682146943021170325866479407987761019956931934065669737733844970field.constant, 4106833857706706417652949425395842926674588555313
556065852954705212767334548field.constant], [5196247641080157421214976259470019902011109253162446920598369271583914387912field.constant, 6360624992789526556614108772011
303405529807087502693775123890278812066474754field.constant, 8425833359837698797187325575646708254811496588866812335451071326764069753553field.constant], [7571765444928
048488636382364785227388831860339901373587410494373985769122100field.constant, 1146560176939543249528183531911179059346379826648787355971780563762045417939field.constan
t, 7065673187452873657602174269205792331276819829797382751854008973390840650347field.constant], [29968862321443948822376004002697590493818366123410751687146744197154244
95381field.constant, 7668744387648470169368229696434415530109096020857128629089289952099341334341field.constant, 9366276989810269197324960237890412883943755006022549114
70718843646602645053field.constant], [6199749224785668013863210092063343076018531979597999604829468825162260274190field.constant, 16531322346798588204823832052714897330
07453315887823778464537322543673289375field.constant, 7939359542319254103812635759696217625861967838748888560647186882218141754398field.constant], [52501473942118181785
24181700154433748053992647055590962793825894928645733326field.constant, 235902753941634492088451291363018081809625358810315316265161104829935550542field.constant, 66089
63137139961850002639926351347514621255004982055637993898513250013620207field.constant], [686840635267965663175276645211808051025823527505028096239338481540935993835fiel
d.constant, 6836915689880452140045500520891176609600850753468429607484223074627863622754field.constant, 4411311036661487117682008390277121256586135166845650218368031395
328640568455field.constant], [7765580651637884064091086941299831107821005732883926779656422881469118342677field.constant, 3325497543848275395525165833314364826260271686
28972328124682073094327566178field.constant, 8438579169602499403531276834153862236681805902767396281885988675130427183942field.constant], [43712243920514441415382167178
30171873522813314722974453159288159086172590441field.constant, 4471819188266525256545603690402039960553559029943278641513107103995534212653field.constant, 7934285249368
611074358220926618133755594116808280441387064776330233673680433field.constant], [3296929004083914338419828203502973195235748568216135964056267831058260996338field.const
ant, 7828705062628438916991665037339807083733865061668384262916273779860279371794field.constant, 63133583805052576390051757683947454002565280685807769464350543339308104
25918field.constant], [7673091158517942236320201239127705985446414040558434294512441355493079388101field.constant, 35898394317874817993354762817669616405924327508846808
04513596535388211513959field.constant, 3497309798506406648010286927425548038594271991920637549888387014860982947288field.constant], [35989285318421892580277446613772201
55690961099878644839237443661252156892627field.constant, 8323476545439527339398168929351847585459351691146904838200536423836775797722field.constant, 2525233425021205371
462807301191193452372106809085080242885832543937723343824field.constant], [1670123541208150697178760793866430341950571765422973242642698972122650175931field.constant, 2
615994352824306042392204336460002628039562926557752567316988279659549764738field.constant, 3845612285742795068547496524855308821681721826554794539870518271238257264872f
ield.constant], [8111729937113136682593516470591971173110681064547090000686075778488505769131field.constant, 83960098870886997120993904887778982954720026490263417422554
74271675851100167field.constant, 7414449034416524223782013238252312102346828190465700203171291370882467344947field.constant], [37783087694226831434276779778661547048535
08570989688082271648398982585170107field.constant, 2565370813801956884760401215151019368813258954878221563399238313359761598300field.constant, 7277843344904687178893605
017520459777796065293383180828267621160222576167983field.constant], [6533305346353864830435743885484797433819452357103761181561861553139604158691field.constant, 7023616
807188225486961828699414844137821383541366139971758751915067616890468field.constant, 6455936034448761051686329703810283225146169133435552271890713431685063292826field.c
onstant], [2781819771186595572605878483518345975589831093852202671865373784050027047498field.constant, 77689208982673719997357826769036818415006784472936071268149239732
94043875457field.constant, 6463549363657422809088424260159871142005366302883731565233242485772646214776field.constant], [42690339398443833366364763604317316186199655240
39119758847937142713481376709field.constant, 5618036788017776315188246458501777138795420885496187406031735668173200947333field.constant, 1128431213282240763420656004648
057492974288942591424362188971631793337713791field.constant], [6900739195883338461228609955335408882714240356250551921341894223851444718631field.constant, 3771335365721
990684607605930021444592509300370948450043449389607062564762590field.constant, 4101659620264578558029808267598816776989279597141521237379858078563415422176field.constan
t], [7265965499850925058171553371274334440963706378337393611300731052328159723420field.constant, 47660787746362906356295656072864978390441568263398944161384106806275721
32174field.constant, 6432220484581857509344049161489739648526811837695982886809250552529276108059field.constant], [63613651895194229804335043841402231389781922128382263
87265114914908491362931field.constant, 7610377774980016354219333532677870219839779550900332138169496134065793623856field.constant, 3631809430301138659429939534614744836
59264066502549823448101062593623940092field.constant], [3562244767885763851343292605940116818317029725206904934994049890929589055395field.constant, 77825492274827728850
45540707357099585281118980712854335622177919009966444948field.constant, 1275552603578693917501370061277948491143012995771911804618466157236333967239field.constant], [51
04148721380689096094143534135757186465840305075873333902995773940524349076field.constant, 3827555903928560008785730325772720209567461775844698712063218244346202837926fi
eld.constant, 6537952092752701292661689328736100739363623229800800023575262375504637794811field.constant], [262555578728776831553731186980980118427004795778856451528099
6906803464172085field.constant, 2268046926631224821219360422346148209575446526490776085639666316914303207343field.constant, 83019857902339750964062939027985231684007559
23104779849614021896827941122062field.constant], [6186410907907226666421909877388154922245464592386712702411681535145025981542field.constant, 15701971147532475267038062
68420919303949793186535455032181860083077073573260field.constant, 6433616921731463425493337442585921501113569311931762833956390491384184622184field.constant], [37307159
29874541583946502538607860277000019933547155277889700636306045698678field.constant, 4162712607911623590542516061947062496983700183068013598513127619182396118738field.co
nstant, 4885581468925689451043482261642022591161185334411569876922526171563347772487field.constant], [679010986662603253067780482929422410547319947222192616893132766589
997651700field.constant, 7045332371454775389874918027434858274122123892961682451412342124928285105115field.constant, 796483939088841221822094384379289433804847199444006
131260701274900329521826field.constant], [6930777873598706215302735286927888271122111082058406024378887982572264481712field.constant, 3833261336312955683233981899122259
611841384124139797023838966596495768744423field.constant, 6081952172694136481884686958014712088378824178559544670607383857565862846284field.constant], [3816381396460078
181431529965953560061945407168453302734314638292833792891390field.constant, 56734387980297685686110088096585973744605712015961903089771968507489169889field.constant, 15
28381975769046861077120384272922840572114805411576866912148437940560430592field.constant], [4051427337822729290390706006634045761150954597129823553613464074823819976689
field.constant, 928801883926308717594921627141285880564599719525707838888160095066522021660field.constant, 2575814441780474908465005749689528467553680700052052921662671
958906858409792field.constant], [4188482005041843983756841875722811236284873807578170011114849822278345286775field.constant, 2055640774204777367415844703991682482137697
203553277498227758201416424138567field.constant, 4575553062307433825409075011087260276527850105624870927391350382554634786094field.constant], [1854996916655462786356197
865726500413712215270951193953965916926815164398288field.constant, 4106990062567081635175461840146829007165341060131472749713325730182145598945field.constant, 4440684113159162228103294475409844107272920293202271745070427054893404635089field.constant]]
)";

    QString mds_str = R"([[6093452032963406658309134825240609333033222270199073508119142384975416392638field.constant, 596827317356286783721000874496674523092376115842896810180757309884085
0097286field.constant, 1100466639266852149977689148055725793531897994956807001704693611715839541982field.constant], [316098360153284417186480285064849228986214799787409
4785600836495095965353712field.constant, 2338351297827692414112631814274572996809824929139580588221558887342663769892field.constant, 31770050879034043434853992829205556
15020488967881372266904325860698809358885field.constant], [2285176219817854683696635383059984246218458246545520061123961933072089703485field.constant, 84377861777946561525373172505381054389617879929776365352216307785104476701field.constant, 8280884008678095605415834125731826663585461281789631237939546251146561093166field.constant]]   
)";

    auto strToVec = [](QString str)->QByteArray {
        str.replace(" ", "");
        str.replace("\n", "");
        str.replace("field.constant", "");
        str.replace("[", "");
        str.replace("]", "");

        QByteArray ret;
        QStringList row = str.split(",");
        for (int i = 0; i < row.size(); i++)
        {
            QByteArray f_row;
            b_uint256_t data(qPrintable(row[i]));

            QByteArray buffer(32,0);
            boost::multiprecision::export_bits(data, buffer.data(), 8, false);

            ret.append(buffer);
        }
        return ret;
    };

    QByteArray p = strToVec(p_str);
    QByteArray psd2 = strToVec("3995586141740408784790749539393");
    psd2.append(strToVec(ark_str));
    psd2.append(strToVec(mds_str));

    init_constant(Constant_P, p.data(),p.size());
    init_constant(Constant_Psd2, psd2.data(), psd2.size());
}

void test_program()
{
    Program program;    
    QString code = readFile("D:/work/test/program.txt");
    Compiler c;
    if (!c.compiler(code, &program))
    {
        qDebug() << "compiler failed: " + c.error();
        return;
    }

    Prover prover;
    prover.program = &program;
    prover.epoch_hash = (char *)epoch_hash_bytes;
    prover.address = (char*)address_bytes;

    QVector<uint64_t> traget;
    traget.resize(1);
    exectuor_run(&prover, traget.data(), traget.size());
}

bool check_rust(const char* dest, const char* variables, uint64_t hash)
{
    if (!isRustInit())
        initRustApi();

    g_checkInst = false;
    QString cmd_line = g_inst;
    QString output = dest;
    QStringList new_variables;
    if(!QString(variables).isEmpty())
        new_variables = QString(variables).split(",");

    RustInstResult rust_ret = rustInstTest(g_inst);
    if (!rust_ret.error.isEmpty())
    {
        qDebug().noquote() << cmd_line << "-> call rust failed: " << rust_ret.error;
        return false;
    }

    auto remove_var = [](QString input) {
        if (input.endsWith(".private"))
            return input.left(input.size() - 8);
        else if (input.endsWith(".public"))
            return input.left(input.size() - 7);

        return input;
    };
    if (remove_var(rust_ret.output) != remove_var(output))
    {
        qDebug().noquote() << cmd_line << "-> output not match, my" << output << ", rust" << rust_ret.output;
        return false;
    }

    if (rust_ret.newVariable.size() != new_variables.size())
    {
        qDebug().noquote() << cmd_line << "-> newVariable size not match, my" << new_variables.size() << ", rust" << rust_ret.newVariable.size();
        return false;
    }
    else
    {
        for (int i = 0; i < new_variables.size(); i++)
        {
            QString field_str = new_variables[i];
            if (field_str != rust_ret.newVariable[i])
            {
                qDebug().noquote() << cmd_line << QString("-> newVariable not match idx %1,my %2, rust %3").arg(QString::number(i), field_str, rust_ret.newVariable[i]);
                return false;
            }
        }
    }

    g_checkInst = true;
    return true;
}

bool test_inst(QString line)
{
    line = line.simplified();

    QStringList str_list = line.split("#");
    if (str_list.size() != 2)
    {
        qDebug() << "parse inst failed,inst:" << line;
        return false;
    }

    int reg_num = 0;
    QStringList inst_regs = str_list[0].trimmed().split(" ", Qt::SkipEmptyParts);

    QString param_line = str_list[1].simplified();
    QStringList params = param_line.split(" ", Qt::SkipEmptyParts);
    for (int i = 1; i < inst_regs.size(); i++)
    {
        if (inst_regs[i].startsWith("r"))
            reg_num++;
    }

    Program program;
    QStringList immType = {"boolean","i8","i16","i32","i64","i128","u8","u16","u32","u64","u128","field"};
    
    QString code;
    for (int i = 0; i < params.size(); i++)
    {
        QString type;
        for (auto t : immType)
        {
            if (params[i] == "true" || params[i] == "false")
            {
                type = "boolean";
                break;
            }
            else if (params[i].endsWith(t))
            {
                type = t;
                break;
            }
        }

        if (type.isEmpty())
        {
            qDebug() << "input error";
            return false;
        }

        code += "input r" + QString::number(i) + " as " + type + ".public;\n";
    }
    code += str_list[0];

    Compiler c;
    if (!c.compiler(code, &program))
    {
        qDebug() << "compiler failed: " + c.error();
        return false;
    }

    Prover prover;
    prover.program = &program;
    prover.epoch_hash = (char*)epoch_hash_bytes;
    prover.address = (char*)address_bytes;

    g_inst = line;
    g_checkInst = false;
    exectuor_run_inst(&prover, qPrintable(param_line));
    return g_checkInst;
}

void test_inst_file()
{
    //auto lines = readFile("/home/qmxiong/work/test/snarkvm_cuda/test/inst.txt").split("\n");
    auto lines = readFile("D:/work/test/inst.txt").split("\n");
    for (int i = 0; i < lines.size(); i++)
    {
        auto line = lines[i].simplified();
        if (line.isEmpty() || line.startsWith("//"))
            continue;

        if (!test_inst(line))
            break;
    }
}

void test_bigint()
{
    std::random_device rd;
    std::mt19937_64 gen(rd());

    // 定义一个分布，这里是均匀分布，范围是int64_t的最小值到最大值
    std::uniform_int_distribution<int64_t> dis(std::numeric_limits<int64_t>::min(), std::numeric_limits<int64_t>::max());

    int64_t ia, ib, ic;
    SignedInteger<64> a, b, c;
    for (int i = 0; i < 1000; i++)
    {
        ia = dis(gen);
        ib = dis(gen);

        a = ia;
        b = ib;
        
        ic = ia + ib;
        c = a + b;
        Q_ASSERT(c == ic);

        ic = ia - ib;
        c = a - b;
        Q_ASSERT(c == ic);

        ic = ia * ib;
        c = a * b;
        Q_ASSERT(c == ic);

        if (ib != 0)
        {
            ic = ia / ib;
            c = a / b;
            Q_ASSERT(c == ic);

            ic = ia % ib;
            c = a % b;
            Q_ASSERT(c == ic);
        }

        ic = -ia;
        c = -a;
        Q_ASSERT(c == ic);

        ic = -ib;
        c = -b;
        Q_ASSERT(c == ic);
    }
}

void test_benchmark()
{
    const char* str_a = "1190687033964617547056118587042553449025443736118671705163780758904113019836";
    const char* str_b = "429452070213179195952166439130853923032362627141776629688605785979843267994";

    b_uint256_t b_a(str_a), b_b(str_b),b_c;
    uint256_t a, b,c;
    
    a = uint256_t::fromString(str_a);
    b = uint256_t::fromString(str_b);


    QElapsedTimer t;
    t.start();
    for (int i = 0; i < 10000000; i++)
    {
        b_c = b_a / b_b;
    }
    qDebug() << "boost:" << t.restart();

    for (int i = 0; i < 10000000; i++)
    {
        c = a / b;
    }
    qDebug() << "my:" << t.elapsed();
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    init_device_constant();

    //test_bigint();
    test_benchmark();
    //test_program();
    //test_inst_file();
 
    //cudaDeviceSynchronize();
    
    return 0;
}
